#include "jpg.h"

// 参数说明：
//   jpgdata: jpg图片数据
//   jpgsize: jpg图片大小
// 返回值说明：
//   成功：指向rgb数据的指针
//   失败：NULL
void jpg2rgb(const char *jpgdata, size_t jpgsize, struct img_info *jpginfo)
{
    // 1，声明解码结构体，以及错误管理结构体
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    // 2，使用缺省的出错处理来初始化解码结构体
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);

    // 3，配置该cinfo，使其从 jpgdata 中读取jpgsize个字节
    //    这些数据必须是完整的JPEG数据
    jpeg_mem_src(&cinfo, jpgdata, jpgsize);

    // 4，读取JPEG文件的头，并判断其格式是否合法
    if(!jpeg_read_header(&cinfo, true))
    {
        fprintf(stderr, "jpeg_read_header failed: "
            "%s\n", strerror(errno));
        return;
    }

    // 5，开始解码
    jpeg_start_decompress(&cinfo);

    // 6，获取图片的尺寸信息a（1. 需要注意的地方）
    jpginfo->width  = cinfo.output_width;
    jpginfo->height = cinfo.output_height;
    jpginfo->bpp    = cinfo.output_components*8;
    jpginfo->size   = jpginfo->width * jpginfo->height * jpginfo->bpp/8;

    int row_stride = jpginfo->width * jpginfo->bpp/8;

    // 7，根据图片的尺寸大小，分配一块相应的内存rgbdata
    //    用来存放从jpgdata解码出来的图像数据
    unsigned long linesize = cinfo.output_width * cinfo.output_components;
    unsigned long rgbsize  = linesize * cinfo.output_height;
    jpginfo->rgb = calloc(1, rgbsize); // （2. 需要注意的地方）

    // 8，循环地将图片的每一行读出并解码到rgb_buffer中
    int line = 0;
    while(cinfo.output_scanline < cinfo.output_height)
    {
        unsigned char *buffer_array[1];
        buffer_array[0] = jpginfo->rgb + cinfo.output_scanline * linesize;
        jpeg_read_scanlines(&cinfo, buffer_array, 1);
    }

    // 9，解码完了，将jpeg相关的资源释放掉
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
}


void load_jpg(const char *jpgfile, struct img_info *jpginfo)
{
    FILE *fp = fopen(jpgfile, "r");

    // 读取jpg数据
    struct stat finfo;
    stat(jpgfile, &finfo);
    char *jpgdata = calloc(1, finfo.st_size);

    // 加载JPG数据
    int n, total=0, jpgsize=finfo.st_size;
    while(jpgsize > 0)
    {
        n = fread(jpgdata+total, 1, jpgsize, fp); // n就是实际读到的字节数

        jpgsize -= n;
        total   += n;
    }
    printf("total: %d\n", total);

    // 调用jpg2rgb
    jpg2rgb(jpgdata, finfo.st_size, jpginfo);
    printf("图片尺寸：%d × %d （色深%d比特）\n", jpginfo->width,
                                                jpginfo->height,
                                                jpginfo->bpp);
    fclose(fp);
}

void show_img(struct lcd_info *lcdinfo, const char *filename)
{
    // 加载图片信息
    struct img_info *jpginfo = calloc(1, sizeof(struct img_info));
    load_jpg(filename, jpginfo);

    // 清屏
    clean_screen(lcdinfo);

    // 居中指针
    int x, y;
    x = lcdinfo->width>jpginfo->width   ? (lcdinfo->width  - jpginfo->width) /2 : 0;
    y = lcdinfo->height>jpginfo->height ? (lcdinfo->height - jpginfo->height)/2 : 0;
    char *tmp = lcdinfo->fb_mem + (800*((y>0)?(y-1):y) + x)*4;

    int wlcd = lcdinfo->width  - x;
    int hlcd = lcdinfo->height - y;

    for(int h=0; h<jpginfo->height && h<hlcd; h++)
    {
        int lcd_offset = lcdinfo->width * 4 * h;
        int rgb_offset = jpginfo->width * 3 * h;

        // 显示一行
        for(int w=0; w<jpginfo->width && w<wlcd; w++)
        {
            memcpy(tmp + 4*w + lcd_offset+2, jpginfo->rgb + 3*w + rgb_offset+0, 1);
            memcpy(tmp + 4*w + lcd_offset+1, jpginfo->rgb + 3*w + rgb_offset+1, 1);
            memcpy(tmp + 4*w + lcd_offset+0, jpginfo->rgb + 3*w + rgb_offset+2, 1);
        }
    }
}

void release_jpg(struct img_info *jpginfo)
{
    // ..
}